//
//  UIImage+SGExtension.swift
//  QingLiuSwift
//
//  Created by xyanl on 2024/11/11.
//  Copyright © 2024 考拉🐨. All rights reserved.
//

import UIKit
import Foundation
import AVFoundation

extension UIImage: SpadgerCompatible {}

// MARK: - 基本的扩展
public extension Spadger where Base: UIImage {
    
    // MARK: 1.1、设置图片的圆角
    /// 设置图片的圆角
    /// - Parameters:
    ///   - radius: 圆角大小 (默认:3.0,图片大小)
    ///   - corners: 切圆角的方式
    ///   - imageSize: 图片的大小
    /// - Returns: 剪切后的图片
    func isRoundCorner(radius: CGFloat = 3, byRoundingCorners corners: UIRectCorner = .allCorners, imageSize: CGSize?) -> UIImage? {
        var drawSize = imageSize ?? base.size
        if drawSize.width <= 0 || drawSize.height <= 0 {
            drawSize = base.size
        }
        // 防止size：(0, 0)崩溃
        if drawSize.width <= 0 || drawSize.height <= 0 {
            drawSize = CGSize(width: 1, height: 1)
        }
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: drawSize)
        // 开始图形上下文
        UIGraphicsBeginImageContextWithOptions(drawSize, false, UIScreen.main.scale)
        guard let contentRef: CGContext = UIGraphicsGetCurrentContext() else {
            // 关闭上下文
            UIGraphicsEndImageContext()
            return nil
        }
        // 绘制路线
        contentRef.addPath(UIBezierPath(
            roundedRect: rect,
            byRoundingCorners: UIRectCorner.allCorners,
            cornerRadii: CGSize(width: radius, height: radius)).cgPath)
        
        // 裁剪
        contentRef.clip()
        // 将原图片画到图形上下文
        base.draw(in: rect)
        contentRef.drawPath(using: .fillStroke)
        guard let output = UIGraphicsGetImageFromCurrentImageContext() else {
            // 关闭上下文
            UIGraphicsEndImageContext()
            return nil
        }
        // 关闭上下文
        UIGraphicsEndImageContext()
        return output
    }
    
    // MARK: 1.2、设置圆形图片
    /// 设置圆形图片
    /// - Returns: 圆形图片
    func isCircleImage() -> UIImage? {
        return isRoundCorner(radius: (self.base.size.width < self.base.size.height ? self.base.size.width : self.base.size.height) / 2.0, byRoundingCorners: .allCorners, imageSize: self.base.size)
    }
    
    // MARK: 1.5、设置图片透明度
    /// 设置图片透明度
    /// alpha: 透明度
    /// - Returns: newImage
    func imageByApplayingAlpha(_ alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContext(base.size)
        let context = UIGraphicsGetCurrentContext()
        let area = CGRect(x: 0, y: 0, width: base.size.width, height: base.size.height)
        context?.scaleBy(x: 1, y: -1)
        context?.translateBy(x: 0, y: -area.height)
        context?.setBlendMode(.multiply)
        context?.setAlpha(alpha)
        context?.draw(self.base.cgImage!, in: area)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage ?? self.base
    }
    
    // MARK: 1.6、裁剪给定区域
    /// 裁剪给定区域
    /// - Parameter crop: 裁剪区域
    /// - Returns: 剪裁后的图片
    func cropWithCropRect( _ crop: CGRect) -> UIImage? {
        let cropRect = CGRect(x: crop.origin.x * self.base.scale, y: crop.origin.y * self.base.scale, width: crop.size.width * self.base.scale, height: crop.size.height *  self.base.scale)
        if cropRect.size.width <= 0 || cropRect.size.height <= 0 {
            return nil
        }
        var image: UIImage?
        autoreleasepool{
            if let cgImage = self.base.cgImage {
                let imageRef: CGImage? = cgImage.cropping(to: cropRect)
                if let imageRef = imageRef {
                    image = UIImage(cgImage: imageRef)
                }
            }
        }
        return image
    }
    
    // MARK: 1.7、裁剪中间的size图片
    /// 裁剪中间的size图片
    /// - Parameter crop: 中间裁剪的size
    /// - Returns: 剪裁后的图片
    func cropCenterSize( _ cropSize: CGSize) -> UIImage? {
        let cropRect = CGRect(
            x: (self.base.size.width - cropSize.width) * self.base.scale / 2.0,
            y: (self.base.size.height - cropSize.height) * self.base.scale / 2.0,
            width: cropSize.width * self.base.scale,
            height: cropSize.height *  self.base.scale
        )
        if cropRect.size.width <= 0 || cropRect.size.height <= 0 || cropRect.size.width > self.base.size.width || cropRect.size.height > self.base.size.height {
            return nil
        }
        var image: UIImage?
        autoreleasepool {
            if let cgImage = self.base.cgImage {
                let imageRef: CGImage? = cgImage.cropping(to: cropRect)
                if let imageRef = imageRef {
                    image = UIImage(
                        cgImage: imageRef,
                        scale: self.base.scale,
                        orientation: self.base.imageOrientation
                    )
                }
            }
        }
        return image
    }
    
    // MARK: 1.8、裁剪中间的px的size图片
    /// 裁剪中间的px的size图片
    /// - Parameter crop: 中间裁剪的size
    /// - Returns: 剪裁后的图片
    func cropCenterPxSize( _ cropPxSize: CGSize) -> UIImage? {
        let cropRect = CGRect(
            x: (self.base.size.width * self.base.scale  - cropPxSize.width) / 2.0,
            y: (self.base.size.height * self.base.scale - cropPxSize.height) / 2.0,
            width: cropPxSize.width,
            height: cropPxSize.height
        )
        if cropRect.size.width <= 0 || cropRect.size.height <= 0 || cropRect.size.width > self.base.size.width * self.base.scale || cropRect.size.height > self.base.size.height * self.base.scale {
            return nil
        }
        var image: UIImage?
        autoreleasepool{
            if let cgImage = self.base.cgImage {
                let imageRef: CGImage? = cgImage.cropping(to: cropRect)
                if let imageRef = imageRef {
                    image = UIImage(cgImage: imageRef, scale: self.base.scale, orientation: self.base.imageOrientation)
                }
            }
        }
        return image
    }
    
    // MARK: 1.9、给图片添加文字水印
    /// 给图片添加文字水印
    /// - Parameters:
    ///   - drawTextframe: 水印的 frame
    ///   - drawText: 水印文字
    ///   - withAttributes: 水印富文本
    /// - Returns: 返回水印图片
    func drawTextInImage(drawTextframe: CGRect, drawText: String, withAttributes: [NSAttributedString.Key : Any]? = nil) -> UIImage {
        // 开启图片上下文
        UIGraphicsBeginImageContext(self.base.size)
        // 图形重绘
        self.base.draw(in: CGRect(x: 0, y: 0, width: self.base.size.width, height: self.base.size.height))
        // 水印文字属性
        let attributes = withAttributes
        // 水印文字和大小
        let text = NSString(string: drawText)
        // 获取富文本的 size
        // let size = text.size(withAttributes: attributes)
        // 绘制文字
        text.draw(in: drawTextframe, withAttributes: attributes)
        // 从当前上下文获取图片
        let image = UIGraphicsGetImageFromCurrentImageContext()
        // 关闭上下文
        UIGraphicsEndImageContext()
        
        return image!
    }
    
    // MARK: 1.10、添加图片水印
    /// 添加图片水印
    /// - Parameters:
    ///   - rect: 水印图片的位置
    ///   - image: 水印图片
    /// - Returns: 带有水印的图片
    func addImageWatermark(rect: CGRect, image: UIImage) -> UIImage? {
        UIGraphicsBeginImageContext(base.size)
        base.draw(in: CGRect.init(x: 0, y: 0, width: base.size.width, height: base.size.height))
        image.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    
    // MARK: 1.11、文字图片占位符
    /// 文字图片占位符
    /// - Parameters:
    ///   - text: 图片上的文字
    ///   - size: 图片的大小
    ///   - backgroundColor: 图片背景色
    ///   - textColor: 文字颜色
    ///   - isCircle: 是否要圆角
    ///   - isFirstChar: 是否展示第一个字符
    /// - Returns: 返回图片
    static func textImage(_ text: String, fontSize: CGFloat = 16, size: (CGFloat, CGFloat), backgroundColor: UIColor = UIColor.orange, textColor: UIColor = UIColor.white, isCircle: Bool = true, isFirstChar: Bool = false) -> UIImage? {
        // 过滤空内容
        if text.isEmpty { return nil }
        // 取第一个字符(测试了,太长了的话,效果并不好)
        let letter = isFirstChar ? (text as NSString).substring(to: 1) : text
        let sise = CGSize(width: size.0, height: size.1)
        let rect = CGRect(origin: CGPoint.zero, size: sise)
        
        let textsize = text.sg.size(width: UIScreen.main.bounds.width, font: .systemFont(ofSize: fontSize))
        
        // 开启上下文
        UIGraphicsBeginImageContext(sise)
        // 拿到上下文
        guard let ctx = UIGraphicsGetCurrentContext() else { return nil }
        // 取较小的边
        let minSide = min(size.0, size.1)
        // 是否圆角裁剪
        if isCircle {
            UIBezierPath(roundedRect: rect, cornerRadius: minSide * 0.5).addClip()
        }
        // 设置填充颜色
        ctx.setFillColor(backgroundColor.cgColor)
        // 填充绘制
        ctx.fill(rect)
        let attr = [NSAttributedString.Key.foregroundColor : textColor, NSAttributedString.Key.font : UIFont.systemFont(ofSize: fontSize)]
        // 写入文字
        // 文字写入的起点
        let pointX: CGFloat = textsize.width > minSide ? 0 : (minSide - textsize.width) / 2.0
        let pointY: CGFloat = (minSide - fontSize - 4) / 2.0
        (letter as NSString).draw(at: CGPoint(x: pointX, y: pointY), withAttributes: attr)
        // 得到图片
        let image = UIGraphicsGetImageFromCurrentImageContext()
        // 关闭上下文
        UIGraphicsEndImageContext()
        return image
    }
    
    // MARK: 1.12、更改图片颜色
    /// 更改图片颜色
    /// - Parameters:
    ///   - color: 图片颜色
    ///   - blendMode: 模式
    /// - Returns: 返回更改后的图片颜色
    func tint(color: UIColor, blendMode: CGBlendMode = .destinationIn) -> UIImage? {
        /**
         有时我们的App需要能切换不同的主题和场景，希望图片能动态的改变颜色以配合对应场景的色调。虽然我们可以根据不同主题事先创建不同颜色的图片供调用，但既然用的图片素材都一样，还一个个转换显得太麻烦，而且不便于维护。使用blendMode变可以满足这个需求。
         */
        defer {
            UIGraphicsEndImageContext()
        }
        let drawRect = CGRect(x: 0, y: 0, width: self.base.size.width, height: self.base.size.height)
        // 防止size：(0, 0)崩溃
        var drawSize = self.base.size
        if drawSize.width <= 0 || drawSize.height <= 0 {
            drawSize = CGSize(width: 1, height: 1)
        }
        UIGraphicsBeginImageContextWithOptions(drawSize, false, self.base.scale)
        color.setFill()
        UIRectFill(drawRect)
        self.base.draw(in: drawRect, blendMode: CGBlendMode.destinationIn, alpha: 1.0)
        guard let tintedImage = UIGraphicsGetImageFromCurrentImageContext() else {
            return nil
        }
        return tintedImage
    }
    
    // MARK: 1.13、获取图片某一个位置像素的颜色
    /// 获取图片某一个位置像素的颜色
    /// - Parameter point: 图片上某个点
    /// - Returns: 返回某个点的 UIColor
    func pixelColor(_ point: CGPoint) -> UIColor? {
        if point.x < 0 || point.x > base.size.width || point.y < 0 || point.y > base.size.height {
            return nil
        }
        
        let provider = self.base.cgImage!.dataProvider
        let providerData = provider!.data
        let data = CFDataGetBytePtr(providerData)
        
        let numberOfComponents: CGFloat = 4.0
        let pixelData = (base.size.width * point.y + point.x) * numberOfComponents
        
        let r = CGFloat(data![Int(pixelData)]) / 255.0
        let g = CGFloat(data![Int(pixelData) + 1]) / 255.0
        let b = CGFloat(data![Int(pixelData) + 2]) / 255.0
        let a = CGFloat(data![Int(pixelData) + 3]) / 255.0
        
        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
    
    // MARK: 1.14、保存图片到相册
    /// 保存图片到相册
    func saveImageToPhotoAlbum(_ result: ((Bool) -> Void)?) {
        base.saveToPhotoAlbum(result)
    }
    
    // MARK: 1.16、图片的模糊效果（高斯模糊滤镜）
    /// 图片的模糊效果（高斯模糊滤镜）
    /// - Parameter fuzzyValue: 设置模糊半径值（越大越模糊）
    /// - Returns: 返回模糊后的图片
    func getGaussianBlurImage(fuzzyValue: CGFloat = 20) -> UIImage? {
        // 生成的高斯模糊滤镜图片
        blurredPicture(fuzzyValue: fuzzyValue, filterName: "CIGaussianBlur")
    }
    
    // MARK: 1.17、像素化后的图片
    ///像素化后的图片
    /// - Parameter fuzzyValue: 设置模糊半径值（越大越模糊）
    /// - Returns: 返回像素化后的图片
    func getPixellateImage(fuzzyValue: CGFloat = 20) -> UIImage? {
        // 生成的高斯模糊滤镜图片
        blurredPicture(fuzzyValue: fuzzyValue, filterName: "CIPixellate")
    }
    
    /// 图片模糊
    /// - Parameters:
    ///   - fuzzyValue: 设置模糊半径值（越大越模糊）
    ///   - filterName: 模糊类型
    /// - Returns: 返回模糊后的图片
    private func blurredPicture(fuzzyValue: CGFloat, filterName: String) -> UIImage? {
        guard let ciImage = CIImage(image: self.base) else { return nil }
        // 创建高斯模糊滤镜类
        guard let blurFilter = CIFilter(name: filterName) else { return nil }
        // 设置图片
        blurFilter.setValue(ciImage, forKey: kCIInputImageKey)
        // 设置模糊半径值（越大越模糊）
        blurFilter.setValue(fuzzyValue, forKey: filterName == "CIPixellate" ? kCIInputScaleKey : kCIInputRadiusKey)
        // 从滤镜中 取出图片
        guard let outputImage = blurFilter.outputImage else { return nil }
        // 创建上下文
        let context = CIContext(options: nil)
        // 根据滤镜中的图片 创建CGImage
        guard let cgImage = context.createCGImage(outputImage, from: ciImage.extent) else { return nil }
        // 生成的模糊图片
        return UIImage(cgImage: cgImage)
    }
    
    // MARK: 1.18、返回一个将白色背景变透明的UIImage
    /// 返回一个将白色背景变透明的UIImage
    /// - Returns: 白色背景变透明的UIImage
    func imageByRemoveWhiteBg() -> UIImage? {
        let colorMasking: [CGFloat] = [222, 255, 222, 255, 222, 255]
        return transparentColor(colorMasking: colorMasking)
    }
    
    // MARK: 1.19、返回一个将黑色背景变透明的UIImage
    /// 返回一个将黑色背景变透明的UIImage
    /// - Returns: 黑色背景变透明的UIImage
    func imageByRemoveBlackBg() -> UIImage? {
        let colorMasking: [CGFloat] = [0, 32, 0, 32, 0, 32]
        return transparentColor(colorMasking: colorMasking)
    }
    
    private func transparentColor(colorMasking: [CGFloat]) -> UIImage? {
        defer {
            UIGraphicsEndImageContext()
        }
        guard let rawImageRef = self.base.cgImage, let maskedImageRef = rawImageRef.copy(maskingColorComponents: colorMasking) else {
            return nil
        }
        UIGraphicsBeginImageContext(self.base.size)
        guard let context: CGContext = UIGraphicsGetCurrentContext() else {
            return nil
        }
        context.translateBy(x: 0.0, y: self.base.size.height)
        context.scaleBy(x: 1.0, y: -1.0)
        context.draw(maskedImageRef, in: CGRect(x: 0, y: 0, width: self.base.size.width, height: self.base.size.height))
        let result = UIGraphicsGetImageFromCurrentImageContext()
        return result
    }
}

fileprivate extension UIImage {
    
    private struct SGRuntimeKey {
        static var saveBlockKey = UnsafeRawPointer("saveBlock".withCString { $0 })
    }
    
    private var saveBlock: ((Bool) -> Void)? {
        get { objc_getAssociatedObject(self, &SGRuntimeKey.saveBlockKey) as? (Bool) -> Void }
        set { objc_setAssociatedObject(self, &SGRuntimeKey.saveBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
    }
    
    /// 保存图片到相册
    func saveToPhotoAlbum(_ result: ((Bool) -> Void)?) {
        saveBlock = result
        UIImageWriteToSavedPhotosAlbum(self, self, #selector(saveImage(image:didFinishSavingWithError:contextInfo:)), nil)
    }
    
    @objc private func saveImage(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: AnyObject) {
        saveBlock?(error == nil)
    }
}


// MARK: - 五、二维码的处理
public extension Spadger where Base: UIImage {
    // MARK: 5.1、生成二维码图片
    /// 生成二维码图片
    /// - Parameters:
    ///   - content: 二维码里面的内容
    ///   - size: 二维码的大小
    ///   - logoSize: logo的大小
    ///   - logoImage: logo图片
    /// - Returns: 返回生成二维码图片
    static func qrImage(
        with content: String,
        size: CGSize,
        isLogo: Bool = true,
        logoSize: CGSize? = nil,
        logoImage: UIImage? = nil,
        logoRoundCorner: CGFloat? = nil
    ) -> UIImage? {
        // 1、创建名为"CIQRCodeGenerator"的CIFilter
        let filter = CIFilter(name: "CIQRCodeGenerator")
        // 2、将filter所有属性设置为默认值
        filter?.setDefaults()
        // 3、将所需尽心转为UTF8的数据，并设置给filter
        let data = content.data(using: String.Encoding.utf8)
        filter?.setValue(data, forKey: "inputMessage")
        // 4、设置二维码的纠错水平，越高纠错水平越高，可以污损的范围越大
        /*
         L: 7%
         M: 15%
         Q: 25%
         H: 30%
         */
        filter?.setValue("H", forKey: "inputCorrectionLevel")
        // 5、拿到二维码图片，此时的图片不是很清晰，需要二次加工
        guard let outPutImage = filter?.outputImage else { return nil }
        
        return getHDImgWithCIImage(with: outPutImage, size: size, isLogo: isLogo, logoSize: logoSize, logoImage: logoImage, logoRoundCorner: logoRoundCorner)
    }
    
    // MARK: 调整二维码清晰度，添加水印图片
    /// 调整二维码清晰度，添加水印图片
    /// - Parameters:
    ///   - image: 模糊的二维码图片
    ///   - size: 二维码的宽高
    ///   - logoSize: logo的大小
    ///   - logoImage: logo图片
    /// - Returns: 添加 logo 图片后，清晰的二维码图片
    private static func getHDImgWithCIImage(
        with image: CIImage,
        size: CGSize,
        isLogo: Bool = true,
        logoSize: CGSize?,
        logoImage: UIImage? = nil,
        logoRoundCorner: CGFloat? = nil
    ) -> UIImage? {
        let extent = image.extent.integral
        let scale = min(size.width / extent.width, size.height / extent.height)
        //1.创建bitmap
        let width = extent.width * scale
        let height = extent.height * scale
        
        // 创建基于GPU的CIContext对象,性能和效果更好
        let context = CIContext(options: nil)
        // 创建CoreGraphics image
        guard let bitmapImage = context.createCGImage(image, from: extent) else { return nil }
        
        // 创建一个DeviceGray颜色空间
        let cs = CGColorSpaceCreateDeviceGray()
        // CGBitmapContextCreate(void * _Nullable data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, CGColorSpaceRef  _Nullable space, uint32_t bitmapInfo)
        // width：图片宽度像素
        // height：图片高度像素
        // bitsPerComponent：每个颜色的比特值，例如在rgba-32模式下为8
        // bitmapInfo：指定的位图应该包含一个alpha通道
        let bitmapRef = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: CGImageAlphaInfo.none.rawValue) //图形上下文，画布
        bitmapRef?.interpolationQuality = CGInterpolationQuality.none //写入质量
        bitmapRef?.scaleBy(x: scale, y: scale) //调整“画布”的缩放
        bitmapRef?.draw(bitmapImage, in: extent) //绘制图片
        
        //2.保存bitmap到图片
        guard let scaledImage = bitmapRef?.makeImage() else { return nil }
        
        // 清晰的二维码图片
        let outputImage = UIImage(cgImage: scaledImage)
        
        guard isLogo == true, let logoSize = logoSize, let logoImage = logoImage else {
            return outputImage
        }
        
        var newLogo: UIImage = logoImage
        if let newLogoRoundCorner = logoRoundCorner, let roundCornerLogo = logoImage.sg.isRoundCorner(radius: newLogoRoundCorner, byRoundingCorners: .allCorners, imageSize: logoSize) {
            newLogo = roundCornerLogo
        }
        
        // 防止size：(0, 0)崩溃
        var drawSize = outputImage.size
        if drawSize.width <= 0 || drawSize.height <= 0 {
            drawSize = CGSize(width: 1, height: 1)
        }
        // 给二维码加 logo 图
        UIGraphicsBeginImageContextWithOptions(drawSize, false, UIScreen.main.scale)
        outputImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        // 把水印图片画到生成的二维码图片上，注意尺寸不要太大（根据上面生成二维码设置的纠错程度设置），否则有可能造成扫不出来
        let waterImgW = logoSize.width
        let waterImgH = logoSize.height
        let waterImgX = (size.width - waterImgW) * 0.5
        let waterImgY = (size.height - waterImgH) * 0.5
        newLogo.draw(in: CGRect(x: waterImgX, y: waterImgY, width: waterImgW, height: waterImgH))
        let newPicture = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newPicture
    }
    
    // MARK: 5.2、获取图片中二维码数组
    func getImageQRImage() -> [CIQRCodeFeature] {
        let qrcodeImg = self.base as UIImage
        let context = CIContext(options: nil)
        guard let ciImage: CIImage = CIImage(image:qrcodeImg),
              let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]),
              let features = detector.features(in: ciImage) as? [CIQRCodeFeature] else {
            return []
        }
        return features
    }
    
    /// 获取图片每个二维码里面的信息数组
    func getImageQRImageInfo() -> [String] {
        // 遍历所有的二维码，并拿出二维码里面的信息
        getImageQRImage().map { $0.messageString ?? ""}
    }
    
    /// 修正方向图片
    var fixOrientationImage: UIImage {
        if base.imageOrientation == .up {
            return base
        }
        UIGraphicsBeginImageContextWithOptions(base.size, false, base.scale)
        base.draw(in: CGRect(x: 0, y: 0, width: base.size.width, height: base.size.height))
        if let normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
            UIGraphicsEndImageContext()
            return normalizedImage
        } else {
            return base
        }
    }
}


/// 未测试过
extension UIImage {
    // MARK: - 压缩图片大小
    func compressSize(with maxSize: Int) -> Data? {
        // 先判断当前质量是否满足要求，不满足再进行压缩
        guard var finallImageData = jpegData(compressionQuality: 1.0) else { return nil }
        if finallImageData.count / 1024 <= maxSize {
            return finallImageData
        }
        // 先调整分辨率
        var defaultSize = CGSize(width: 1024, height: 1024)
        guard let compressImage = scaleSize(defaultSize), let compressImageData = compressImage.jpegData(compressionQuality: 1.0) else {
            return nil
        }
        finallImageData = compressImageData
        
        // 保存压缩系数
        var compressionQualityArray = [CGFloat]()
        let avg: CGFloat = 1.0 / 250
        var value = avg
        var i: CGFloat = 250.0
        repeat {
            i -= 1
            value = i * avg
            compressionQualityArray.append(value)
        } while i >= 1
        
        // 调整大小，压缩系数数组compressionQualityArr是从大到小存储，思路：使用二分法搜索
        guard let halfData = halfFuntion(array: compressionQualityArray, image: compressImage, sourceData: finallImageData, maxSize: maxSize) else {
            return nil
        }
        finallImageData = halfData
        // 如果还是未能压缩到指定大小，则进行降分辨率
        while finallImageData.count == 0 {
            // 每次降100分辨率
            if defaultSize.width - 100 <= 0 || defaultSize.height - 100 <= 0 {
                break
            }
            defaultSize = CGSize(width: defaultSize.width - 100, height: defaultSize.height - 100)
            guard let lastValue = compressionQualityArray.last,
                  let newImageData = compressImage.jpegData(compressionQuality: lastValue),
                  let tempImage = UIImage(data: newImageData),
                  let tempCompressImage = tempImage.scaleSize(defaultSize),
                  let sourceData = tempCompressImage.jpegData(compressionQuality: 1.0),
                  let halfData = halfFuntion(array: compressionQualityArray, image: tempCompressImage, sourceData: sourceData, maxSize: maxSize)
            else {
                return nil
            }
            finallImageData = halfData
        }
        return finallImageData
    }
    
    /// 压缩图片
    /// - Parameters:
    ///   - width: 压缩后图片的宽度，默认：0，根据手机的scale等比缩小
    ///   - maxSize: 压缩后图片的最大存储
    /// - Returns: 压缩后的图片data，maxSize*0.9 < data.count < maxSize
    func compress(width: CGFloat = 0, maxSize: Int = 1024 * 1024 * 2) -> Data? {
        
        guard let data = self.jpegData(compressionQuality: 1) else { return nil }
        if data.count < maxSize {
            return data
        }
        
        let scale = UIScreen.main.scale
        var resize = CGSize(width: self.size.width / scale, height: self.size.height / scale)
        
        if width > 0 {
            let height = width * self.size.height / self.size.width
            resize = CGSize(width: width, height: height)
        }
        
        guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else { return nil }
        
        let maxPixelSize = max(resize.width, resize.height)
        let options = [
            kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceShouldCacheImmediately: true,
        ] as [CFString : Any]
        
        // 改变image的size
        let resizedImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary).flatMap {
            UIImage(cgImage: $0)
        }
        
        var compression: CGFloat = 1
        var max: CGFloat = 1
        var min: CGFloat = 0
        
        var resultData: Data!
        for _ in 0..<6 {
            compression = (max + min) / 2
            resultData = resizedImage!.jpegData(compressionQuality: compression)!
            // print("data: \(resultData.count) b compression: \(compression)")
            if CGFloat(resultData.count) < CGFloat(maxSize) * 0.9 {
                min = compression
            } else if resultData.count > maxSize {
                max = compression
            } else {
                break
            }
        }
        
        // let size = CGFloat(resultData.count)/1024.0
        // print("result data: \(size) kb")
        return resultData
    }
    
    func resizeIO(resizeSize: CGSize) -> UIImage? {
        guard let imageData = self.pngData() else { return nil }
        guard let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil) else { return nil }
        
        let maxPixelSize = max(resizeSize.width, resizeSize.height)
        let options = [
            kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceCreateThumbnailWithTransform: true,
            
        ] as [CFString : Any]
        
        let resizedImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary).flatMap {
            UIImage(cgImage: $0)
        }
        return resizedImage
    }
    
    
    // MARK: - 调整图片分辨率/尺寸（等比例缩放）
    
    func scaleSize(_ newSize: CGSize) -> UIImage? {
        let heightScale = size.height / newSize.height
        let widthScale = size.width / newSize.width
        
        var finallSize = CGSize(width: size.width, height: size.height)
        if widthScale > 1.0, widthScale > heightScale {
            finallSize = CGSize(width: size.width / widthScale, height: size.height / widthScale)
        } else if heightScale > 1.0, widthScale < heightScale {
            finallSize = CGSize(width: size.width / heightScale, height: size.height / heightScale)
        }
        UIGraphicsBeginImageContext(CGSize(width: Int(finallSize.width), height: Int(finallSize.height)))
        draw(in: CGRect(x: 0, y: 0, width: finallSize.width, height: finallSize.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    
    // MARK: - 二分法
    private func halfFuntion(array: [CGFloat], image: UIImage, sourceData: Data, maxSize: Int) -> Data? {
        var tempFinallImageData = sourceData
        var finallImageData = Data()
        var start = 0
        var end = array.count - 1
        var index = 0
        
        var difference = Int.max
        while start <= end {
            index = start + (end - start) / 2
            guard let data = image.jpegData(compressionQuality: array[index]) else {
                return nil
            }
            tempFinallImageData = data
            let sizeOrigin = tempFinallImageData.count
            let sizeOriginKB = sizeOrigin / 1024
            if sizeOriginKB > maxSize {
                start = index + 1
            } else if sizeOriginKB < maxSize {
                if maxSize - sizeOriginKB < difference {
                    difference = maxSize - sizeOriginKB
                    finallImageData = tempFinallImageData
                }
                if index <= 0 {
                    break
                }
                end = index - 1
            } else {
                break
            }
        }
        return finallImageData
    }
}

/// 未测试过
extension UIImage {
    /// 智能压缩图片大小
    func smartCompressImage() -> Data? {
        guard let finallImageData = jpegData(compressionQuality: 1.0) else { return nil }
        if finallImageData.count / 1024 <= 300 {
            return finallImageData
        }
        var width = size.width
        var height = size.height
        let longSide = max(width, height)
        let shortSide = min(width, height)
        let scale = shortSide / longSide
        if shortSide < 1080 || longSide < 1080 {
            return jpegData(compressionQuality: 0.5)
        } else {
            if width < height {
                width = 1080
                height = 1080 / scale
            } else {
                width = 1080 / scale
                height = 1080
            }
            UIGraphicsBeginImageContext(CGSize(width: width, height: height))
            draw(in: CGRect(x: 0, y: 0, width: width, height: height))
            let compressImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return compressImage?.jpegData(compressionQuality: 0.5)
        }
    }
}

/// 未测试过
extension UIImage {
    /// 灰度算法
    enum GrayscaleAlgorithm {
        /// 平均值
        case average
        /// rec601标准
        case rec601
        /// rec709标准
        case rec709
        /// rec2100标准
        case rec2100
        /// 最大值
        case max
        /// 最小值
        case min
        /// 分量法—红
        case red
        /// 分量法—绿
        case green
        /// 分量法—蓝
        case blue
    }
    
    /// 灰度图
    func grayscale(_ type: GrayscaleAlgorithm) -> UIImage? {
        guard let cgImage else {
            return nil
        }
        
        let imageWidth = Int(size.width * scale)
        let imageHeight = Int(size.height * scale)
        
        guard let pixelBuffer: CVPixelBuffer = {
            let pixelBufferAttributes = [
                kCVPixelFormatCGImageCompatibility: true,
                kCVPixelBufferCGBitmapContextCompatibilityKey: true,
                kCVPixelBufferIOSurfacePropertiesKey: [String: Any](),
            ] as CFDictionary
            
            var pixelBuffer: CVPixelBuffer?
            CVPixelBufferCreate(
                kCFAllocatorDefault,
                imageWidth,
                imageHeight,
                kCVPixelFormatType_32ARGB,
                pixelBufferAttributes,
                &pixelBuffer
            )
            return pixelBuffer
        }() else {
            return nil
        }
        
        CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
        
        let pixelBufferData = CVPixelBufferGetBaseAddress(pixelBuffer)
        
        guard let context = CGContext(
            data: pixelBufferData,
            width: imageWidth,
            height: imageHeight,
            bitsPerComponent: 8,
            bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
            space: CGColorSpaceCreateDeviceRGB(),
            bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue
        ) else { return nil }
        
        context.draw(cgImage, in: CGRect(origin: .zero, size: size.applying(CGAffineTransform(scaleX: scale, y: scale))))
        
        let data = unsafeBitCast(pixelBufferData, to: UnsafeMutablePointer<UInt8>.self)
        
        let row = CVPixelBufferGetBytesPerRow(pixelBuffer) / 4
        let height = CVPixelBufferGetHeight(pixelBuffer)
        
        for y in 0 ..< height {
            for x in 0 ..< row {
                let offset = 4 * (y * row + x)
                
                let gray: UInt8 = {
                    let red = CGFloat(data[offset + 1])
                    let green = CGFloat(data[offset + 2])
                    let blue = CGFloat(data[offset + 3])
                    
                    switch type {
                    case .average:
                        let value = 1.0 / 3.0
                        return UInt8(red * value + green * value + blue * value)
                    case .rec601:
                        return UInt8(red * 0.299 + green * 0.587 + blue * 0.114)
                    case .rec709:
                        return UInt8(red * 0.2126 + green * 0.7152 + blue * 0.0722)
                    case .rec2100:
                        return UInt8(red * 0.2627 + green * 0.6780 + blue * 0.0593)
                    case .max:
                        return UInt8(max(max(red, green), blue))
                    case .min:
                        return UInt8(min(min(red, green), blue))
                    case .red:
                        return UInt8(red)
                    case .green:
                        return UInt8(green)
                    case .blue:
                        return UInt8(blue)
                    }
                }()
                data[offset + 1] = gray
                data[offset + 2] = gray
                data[offset + 3] = gray
            }
        }
        CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
        guard let cgImage = context.makeImage() else {
            return nil
        }
        return UIImage(cgImage: cgImage)
    }
    
    
    static func gradualShadowImage(_ havingSize: CGSize) -> UIImage? {
        let layer = CAGradientLayer.init()
        layer.contentsScale = UIScreen.main.scale
        let blackColor = UIColor.black
        layer.colors = [
            blackColor.withAlphaComponent(0).cgColor,
            blackColor.withAlphaComponent(0.3).cgColor,
            blackColor.withAlphaComponent(0.4).cgColor,
            blackColor.withAlphaComponent(0.5).cgColor,
            blackColor.withAlphaComponent(0.6).cgColor
        ]
        layer.startPoint = CGPoint(x: 0, y: 1)
        layer.endPoint = CGPoint(x: 0, y: 0)
        layer.locations = [0.1, 0.3, 0.5, 0.7, 0.9]
        layer.borderWidth = 0.0
        layer.frame = CGRect(origin: .zero, size: havingSize)
        let format = UIGraphicsImageRendererFormat()
        format.opaque = false
        format.scale = UIScreen.main.scale
        let renderer = UIGraphicsImageRenderer(size: havingSize, format: format)
        let image = renderer.image { context in
            layer.render(in: context.cgContext)
        }
        return image
    }
}


extension UIImage {
    
    /// 获取视频的第一帧
    /// - Parameter url: 视频本地地址
    /// - Returns: 视频的封面
    static func imageFromVideo(_ url: String) -> UIImage? {
        
        let Url = URL(string: url)
        // 获取本地视频
        let asset = AVURLAsset(url: Url!)
        
        // 生成视频截图
        let generator = AVAssetImageGenerator(asset: asset)
        generator.appliesPreferredTrackTransform = true
        
        let time = CMTimeMake(value: 0, timescale: 600)
        var actualTime: CMTime = .zero
        if let cgImage = try? generator.copyCGImage(at: time, actualTime: &actualTime) {
            let image = UIImage(cgImage: cgImage)
            return image
        }
        return nil
    }
    
    //MARK: 获取第一帧当封面
    static func getFirstGen(asset:AVURLAsset) -> UIImage? {
        let assetGen = AVAssetImageGenerator(asset: asset)
        assetGen.appliesPreferredTrackTransform = true
        let time = CMTimeMake(value: 0, timescale: 600)
        var actualTime:CMTime = .zero
        if let cgImage = try? assetGen.copyCGImage(at: time, actualTime: &actualTime) {
            let image = UIImage(cgImage: cgImage)
            return image
        }
        return nil
    }
}
